cssnode: Add API to query the timestamp
authorBenjamin Otte <otte@redhat.com>
Wed, 18 Feb 2015 23:54:14 +0000 (00:54 +0100)
committerBenjamin Otte <otte@redhat.com>
Wed, 18 Mar 2015 14:23:32 +0000 (15:23 +0100)
... and pass it to the API that computes new styles.

A special timestamp of 0 means "please don't animate" and is used when
no frame clock is available for a node.

gtk/gtkcssnode.c
gtk/gtkcssnodeprivate.h
gtk/gtkcsstypes.c
gtk/gtkcsstypesprivate.h
gtk/gtkcsswidgetnode.c
gtk/gtkwidget.c

index 93d5395cc840df7ab022bc111397a0d92e746630..3de1b6ff035b282d3847f7da2d6cecda778d47a4 100644 (file)
@@ -226,6 +226,7 @@ gtk_css_style_needs_recreation (GtkCssStyle  *style,
 static GtkCssStyle *
 gtk_css_node_real_update_style (GtkCssNode   *cssnode,
                                 GtkCssChange  pending_change,
+                                gint64        timestamp,
                                 GtkCssStyle  *old_style)
 {
   if (!gtk_css_style_needs_recreation (old_style, pending_change))
@@ -285,6 +286,12 @@ gtk_css_node_real_get_style_provider (GtkCssNode *cssnode)
   return NULL;
 }
 
+static GdkFrameClock *
+gtk_css_node_real_get_frame_clock (GtkCssNode *cssnode)
+{
+  return NULL;
+}
+
 static void
 gtk_css_node_class_init (GtkCssNodeClass *klass)
 {
@@ -302,6 +309,7 @@ gtk_css_node_class_init (GtkCssNodeClass *klass)
   klass->create_widget_path = gtk_css_node_real_create_widget_path;
   klass->get_widget_path = gtk_css_node_real_get_widget_path;
   klass->get_style_provider = gtk_css_node_real_get_style_provider;
+  klass->get_frame_clock = gtk_css_node_real_get_frame_clock;
 }
 
 static void
@@ -314,6 +322,27 @@ gtk_css_node_init (GtkCssNode *cssnode)
   cssnode->visible = TRUE;
 }
 
+static GdkFrameClock *
+gtk_css_node_get_frame_clock_or_null (GtkCssNode *cssnode)
+{
+  while (cssnode->parent)
+    cssnode = cssnode->parent;
+
+  return GTK_CSS_NODE_GET_CLASS (cssnode)->get_frame_clock (cssnode);
+}
+
+static gint64
+gtk_css_node_get_timestamp (GtkCssNode *cssnode)
+{
+  GdkFrameClock *frameclock;
+
+  frameclock = gtk_css_node_get_frame_clock_or_null (cssnode);
+  if (frameclock == NULL)
+    return 0;
+
+  return gdk_frame_clock_get_frame_time (frameclock);
+}
+
 static void
 gtk_css_node_parent_was_unset (GtkCssNode *node)
 {
@@ -440,6 +469,7 @@ gtk_css_node_reposition (GtkCssNode *node,
 
       if (gtk_css_node_get_style_provider_or_null (node) == NULL)
         gtk_css_node_invalidate_style_provider (node);
+      gtk_css_node_invalidate (node, GTK_CSS_CHANGE_TIMESTAMP | GTK_CSS_CHANGE_ANIMATIONS);
     }
 
   if (parent)
@@ -560,22 +590,30 @@ gtk_css_node_propagate_pending_changes (GtkCssNode *cssnode,
     }
 }
 
+static gboolean
+gtk_css_node_needs_new_style (GtkCssNode *cssnode)
+{
+  return cssnode->style_is_invalid;
+}
+
 static void
-gtk_css_node_ensure_style (GtkCssNode *cssnode)
+gtk_css_node_ensure_style (GtkCssNode *cssnode,
+                           gint64      current_time)
 {
   GtkCssStyle *new_style;
 
-  if (!cssnode->style_is_invalid)
+  if (!gtk_css_node_needs_new_style (cssnode))
     return;
 
   if (cssnode->parent)
-    gtk_css_node_ensure_style (cssnode->parent);
+    gtk_css_node_ensure_style (cssnode->parent, current_time);
 
   if (cssnode->previous_sibling)
-    gtk_css_node_ensure_style (cssnode->previous_sibling);
+    gtk_css_node_ensure_style (cssnode->previous_sibling, current_time);
 
   new_style = GTK_CSS_NODE_GET_CLASS (cssnode)->update_style (cssnode,
                                                               cssnode->pending_changes,
+                                                              current_time,
                                                               cssnode->style);
 
   gtk_css_node_propagate_pending_changes (cssnode, new_style != NULL);
@@ -593,7 +631,12 @@ gtk_css_node_ensure_style (GtkCssNode *cssnode)
 GtkCssStyle *
 gtk_css_node_get_style (GtkCssNode *cssnode)
 {
-  gtk_css_node_ensure_style (cssnode);
+  if (gtk_css_node_needs_new_style (cssnode))
+    {
+      gint64 timestamp = gtk_css_node_get_timestamp (cssnode);
+
+      gtk_css_node_ensure_style (cssnode, timestamp);
+    }
 
   return cssnode->style;
 }
@@ -755,6 +798,20 @@ gtk_css_node_invalidate_style_provider (GtkCssNode *cssnode)
     }
 }
 
+void
+gtk_css_node_invalidate_frame_clock (GtkCssNode *cssnode,
+                                     gboolean    just_timestamp)
+{
+  /* frame clock is handled by the top level */
+  if (cssnode->parent)
+    return;
+
+  if (just_timestamp)
+    gtk_css_node_invalidate (cssnode, GTK_CSS_CHANGE_TIMESTAMP);
+  else
+    gtk_css_node_invalidate (cssnode, GTK_CSS_CHANGE_TIMESTAMP | GTK_CSS_CHANGE_ANIMATIONS);
+}
+
 void
 gtk_css_node_invalidate (GtkCssNode   *cssnode,
                          GtkCssChange  change)
index 944e01fa21dce9dd241411e426a13d1396cd6062..4101037edb85cc1ecfabdf7088f578703bbe4c02 100644 (file)
@@ -70,8 +70,11 @@ struct _GtkCssNodeClass
   const GtkWidgetPath * (* get_widget_path)             (GtkCssNode            *cssnode);
   /* get style provider to use or NULL to use parent's */
   GtkStyleProviderPrivate *(* get_style_provider)       (GtkCssNode            *cssnode);
+  /* get frame clock or NULL (only relevant for root node) */
+  GdkFrameClock *       (* get_frame_clock)             (GtkCssNode            *cssnode);
   GtkCssStyle *         (* update_style)                (GtkCssNode            *cssnode,
                                                          GtkCssChange           pending_changes,
+                                                         gint64                 timestamp,
                                                          GtkCssStyle           *old_style);
   void                  (* invalidate)                  (GtkCssNode            *node);
   void                  (* queue_validate)              (GtkCssNode            *node);
@@ -140,6 +143,9 @@ GtkCssStyle *           gtk_css_node_create_style       (GtkCssNode            *
 
 void                    gtk_css_node_invalidate_style_provider
                                                         (GtkCssNode            *cssnode);
+void                    gtk_css_node_invalidate_frame_clock
+                                                        (GtkCssNode            *cssnode,
+                                                         gboolean               just_timestamp);
 void                    gtk_css_node_invalidate         (GtkCssNode            *cssnode,
                                                          GtkCssChange           change);
 void                    gtk_css_node_validate           (GtkCssNode            *cssnode,
index 46e7c1c26558f2261112ec969f7e126972fc5f1d..6ab3bc5063659f7cd97e8d5d37820a87bab8579b 100644 (file)
@@ -57,7 +57,6 @@ _gtk_css_change_for_sibling (GtkCssChange match)
     { GTK_CSS_CHANGE_POSITION, GTK_CSS_CHANGE_SIBLING_POSITION },
     { GTK_CSS_CHANGE_STATE, GTK_CSS_CHANGE_SIBLING_STATE },
     { GTK_CSS_CHANGE_SOURCE, 0 },
-    { GTK_CSS_CHANGE_ANIMATE, 0 },
     { GTK_CSS_CHANGE_PARENT_STYLE, 0 }
   };
 
@@ -77,7 +76,6 @@ _gtk_css_change_for_child (GtkCssChange match)
     { GTK_CSS_CHANGE_SIBLING_POSITION, GTK_CSS_CHANGE_PARENT_SIBLING_POSITION },
     { GTK_CSS_CHANGE_SIBLING_STATE, GTK_CSS_CHANGE_PARENT_SIBLING_STATE },
     { GTK_CSS_CHANGE_SOURCE, 0 },
-    { GTK_CSS_CHANGE_ANIMATE, 0 },
     { GTK_CSS_CHANGE_PARENT_STYLE, 0 }
   };
 
index d2cd6d3f8e78c7d54584b6fc75263d2832e58d66..1f68e9c39afeacaac315bc804aef982feb3da64d 100644 (file)
@@ -51,8 +51,9 @@ typedef enum { /*< skip >*/
   GTK_CSS_CHANGE_PARENT_SIBLING_STATE     = (1 << 15),
   /* add more */
   GTK_CSS_CHANGE_SOURCE                   = (1 << 16),
-  GTK_CSS_CHANGE_ANIMATE                  = (1 << 17),
-  GTK_CSS_CHANGE_PARENT_STYLE             = (1 << 18),
+  GTK_CSS_CHANGE_PARENT_STYLE             = (1 << 17),
+  GTK_CSS_CHANGE_TIMESTAMP                = (1 << 18),
+  GTK_CSS_CHANGE_ANIMATIONS               = (1 << 19),
 
   GTK_CSS_CHANGE_RESERVED_BIT             = (1 << 31) /* Used internally in gtkcssselector.c */
 } GtkCssChange;
index d3ec5a204384928aede89b3321a2fa230bc0a41b..1bc21244df35701ca45b9ff74bbba01a00f0a3de 100644 (file)
@@ -36,14 +36,28 @@ G_DEFINE_TYPE (GtkCssWidgetNode, gtk_css_widget_node, GTK_TYPE_CSS_NODE)
 static GtkCssStyle *
 gtk_css_widget_node_update_style (GtkCssNode   *cssnode,
                                   GtkCssChange  pending_change,
+                                  gint64        timestamp,
                                   GtkCssStyle  *old_style)
 {
   if (old_style == NULL)
-    return GTK_CSS_NODE_CLASS (gtk_css_widget_node_parent_class)->update_style (cssnode, pending_change, old_style);
+    return GTK_CSS_NODE_CLASS (gtk_css_widget_node_parent_class)->update_style (cssnode, pending_change, timestamp, old_style);
 
   return NULL;
 }
 
+static gboolean
+gtk_css_widget_node_queue_callback (GtkWidget     *widget,
+                                    GdkFrameClock *frame_clock,
+                                    gpointer       user_data)
+{
+  GtkCssNode *node = user_data;
+  
+  gtk_css_node_invalidate_frame_clock (node, TRUE);
+  _gtk_container_queue_restyle (GTK_CONTAINER (widget));
+
+  return G_SOURCE_CONTINUE;
+}
+
 static void
 gtk_css_widget_node_queue_validate (GtkCssNode *node)
 {
@@ -52,8 +66,8 @@ gtk_css_widget_node_queue_validate (GtkCssNode *node)
   G_GNUC_BEGIN_IGNORE_DEPRECATIONS
   if (GTK_IS_RESIZE_CONTAINER (widget_node->widget))
     widget_node->validate_cb_id = gtk_widget_add_tick_callback (widget_node->widget,
-                                                                (GtkTickCallback) _gtk_container_queue_restyle,
-                                                                NULL,
+                                                                gtk_css_widget_node_queue_callback,
+                                                                node,
                                                                 NULL);
   G_GNUC_END_IGNORE_DEPRECATIONS
 }
@@ -128,7 +142,7 @@ gtk_css_widget_node_validate (GtkCssNode       *node,
 
   new_static_style = validate_static_style (node, static_style, change);
 
-  if (new_static_style != static_style)
+  if (new_static_style != static_style || (change & GTK_CSS_CHANGE_ANIMATIONS))
     {
       GtkCssNode *parent = gtk_css_node_get_parent (node);
       new_style = gtk_css_animated_style_new (new_static_style,
@@ -139,7 +153,7 @@ gtk_css_widget_node_validate (GtkCssNode       *node,
       
       g_object_unref (new_static_style);
     }
-  else if (GTK_IS_CSS_ANIMATED_STYLE (style))
+  else if (GTK_IS_CSS_ANIMATED_STYLE (style) && (change & GTK_CSS_CHANGE_TIMESTAMP))
     {
       new_style = gtk_css_animated_style_new_advance (GTK_CSS_ANIMATED_STYLE (style),
                                                       static_style,
@@ -264,6 +278,17 @@ gtk_css_widget_node_get_style_provider (GtkCssNode *node)
   return gtk_style_context_get_style_provider (gtk_widget_get_style_context (widget_node->widget));
 }
 
+static GdkFrameClock *
+gtk_css_widget_node_get_frame_clock (GtkCssNode *node)
+{
+  GtkCssWidgetNode *widget_node = GTK_CSS_WIDGET_NODE (node);
+
+  if (widget_node->widget == NULL)
+    return NULL;
+
+  return gtk_widget_get_frame_clock (widget_node->widget);
+}
+
 static void
 gtk_css_widget_node_class_init (GtkCssWidgetNodeClass *klass)
 {
@@ -277,6 +302,7 @@ gtk_css_widget_node_class_init (GtkCssWidgetNodeClass *klass)
   node_class->create_widget_path = gtk_css_widget_node_create_widget_path;
   node_class->get_widget_path = gtk_css_widget_node_get_widget_path;
   node_class->get_style_provider = gtk_css_widget_node_get_style_provider;
+  node_class->get_frame_clock = gtk_css_widget_node_get_frame_clock;
 }
 
 static void
index cfb4223bfa03703af10a3cadabe01d19840bc7cd..b28ebcfba7f88c85126da1555f223630fed3f44e 100644 (file)
@@ -5446,6 +5446,8 @@ gtk_widget_connect_frame_clock (GtkWidget     *widget,
       gdk_frame_clock_begin_updating (frame_clock);
     }
 
+  gtk_css_node_invalidate_frame_clock (priv->cssnode, FALSE);
+
   if (priv->context)
     gtk_style_context_set_frame_clock (priv->context, frame_clock);
 }
@@ -5459,6 +5461,8 @@ gtk_widget_disconnect_frame_clock (GtkWidget     *widget,
   if (GTK_IS_CONTAINER (widget))
     _gtk_container_stop_idle_sizer (GTK_CONTAINER (widget));
 
+  gtk_css_node_invalidate_frame_clock (priv->cssnode, FALSE);
+
   if (priv->clock_tick_id)
     {
       g_signal_handler_disconnect (frame_clock, priv->clock_tick_id);